#include <qapplication.h>
#include "window.moc"
#include "glwidget.h"

#include "ucdinputfile.h"

#include "visStreamsurface.h"

using namespace visualization;
using std::cout;
using std::endl;

//====================================================================
void normalize(float v[3])
{
	GLfloat d = sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
	if(0.0 == d)
	{
		cout << "zero lenght vector!" << endl;
		return;
	}
	v[0] /= d;
	v[1] /= d;
	v[2] /= d;
}

void normcrossprod(float v1[3], float v2[3], float out[3])
{
	out[0] = v1[1] * v2[2] - v1[2] * v2[1];
	out[1] = v1[2] * v2[0] - v1[0] * v2[2];
	out[2] = v1[0] * v2[1] - v1[1] * v2[0];
	normalize(out);
}
//====================================================================

class glW: public GLWidget
{
public:
	glW(QWidget *parent = 0) 
	     : GLWidget(parent)
	{}
	~glW()
  {
      delete results;
      results = NULL;
	}
private:
	Model t;
	double xmin, xmax, ymin, ymax, zmin, zmax;
	vector<Point> *results;

public:
	GLuint makeObject()
	{
		GLuint list = glGenLists(1);
		glNewList(list, GL_COMPILE);

	// begin
		UCDInputFile file(filename);
		file.FGetModel(t);	
		t.buildKDTree();
		visStreamsurface s(&t);
		s.setIntegrationDouble();

		t.getBound(xmin, xmax, ymin, ymax, zmin, zmax);
	 	double c[3] =
		{
			(xmax + xmin)/2,
			(ymax + ymin)/2,
			(zmax + zmin)/2
		};

		cout << "Input the segments..." << endl;
		size_t m, n = 6;
		cin >> m;
		double **sources = new double*[m];
		for(size_t i = 0; i < m; i++)
			sources[i] = new double[n];

		//Point diag(xmax-xmin, ymax-ymin, zmax - zmin);
		Point diag(xmax-xmin, ymax-ymin, zmax - zmin);
		diag /= m;
		for(size_t i = 0; i < m; i++)
		{
			sources[i][0] = xmin + diag.getX() * i;
			sources[i][1] = ymin + diag.getY() * i;
			sources[i][2] = zmin + diag.getZ() * i;
		}
//
//		sources[0][0] = xmin;
//		sources[0][1] = ymin;
//		sources[0][2] = zmin;
//
//		sources[1][0] = xmin + diag.getX();
//		sources[1][1] = ymin + diag.getY();
//		sources[1][2] = zmin + diag.getZ();
//
//		sources[2][0] = xmin + diag.getX() * 2;
//		sources[2][1] = ymin + diag.getY() * 2;
//		sources[2][2] = zmin + diag.getZ() * 2;
//
//		sources[3][0] = xmin + diag.getX() * 3;
//		sources[3][1] = ymin + diag.getY() * 3;
//		sources[3][2] = zmin + diag.getZ() * 3;
//
//		sources[4][0] = xmin + diag.getX() * 4;
//		sources[4][1] = ymin + diag.getY() * 4;
//		sources[4][2] = zmin + diag.getZ() * 4;
//
//		sources[5][0] = xmin + diag.getX() * 5;
//		sources[5][1] = ymin + diag.getY() * 5;
//		sources[5][2] = zmin + diag.getZ() * 5;

		s.setMultiplePointSources2(1, m, sources);

		for(size_t i = 0; i < m; i++)
			delete []sources[i];
		delete []sources;

		s.setParameters(0.1, 200);

		cout << "constructing streamsurface..." << endl;
		s.constructStreamSurface();
		results = s.getTheStreamSurface();

		cout << "Input the scale..." << endl;
		double scale;
		cin >> scale;
	
		glBegin(GL_LINES);
		drawFramework(xmin-c[0], xmax-c[0], ymin-c[1], ymax-c[1], zmin-c[2], zmax-c[2], scale);
		glEnd();
	
		glLineWidth(1);
		glColor3f((GLfloat)0.1, (GLfloat)1, (GLfloat)0.4);
		glPolygonMode(GL_FRONT, GL_FILL);

		GLfloat d1[3], d2[3], norm[3];

		for(size_t i = 0; i < results->size(); /*i++*/)
		{
  			d1[0] = (*results)[i].getX() - (*results)[i+1].getX();
				d1[1] = (*results)[i].getY() - (*results)[i+1].getY();
				d1[2] = (*results)[i].getZ() - (*results)[i+1].getZ();

				d2[0] = (*results)[i].getX() - (*results)[i+2].getX();
				d2[1] = (*results)[i].getY() - (*results)[i+2].getY();
				d2[2] = (*results)[i].getZ() - (*results)[i+2].getZ();

				normcrossprod(d1, d2, norm);
				glNormal3fv(norm);

				glBegin(GL_TRIANGLES);
				glVertex3f( ((*results)[i].getX() - c[0])/scale, ((*results)[i].getY() - c[1])/scale, ((*results)[i].getZ() - c[2])/scale);
				i++;
				glVertex3f( ((*results)[i].getX() - c[0])/scale, ((*results)[i].getY() - c[1])/scale, ((*results)[i].getZ() - c[2])/scale);
				i++;
				glVertex3f( ((*results)[i].getX() - c[0])/scale, ((*results)[i].getY() - c[1])/scale, ((*results)[i].getZ() - c[2])/scale);
				i++;
				glEnd();
		}

		glEndList();
		return list;
	}
};
class win : public Window
{
public:
	win(glW *glwidget)
		: Window(glwidget)
	{}
	~win(){}
};

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

	glW *glw = new glW();
	if(argc<2)
	{
		cout << "Input the data file please..." << endl;
		return 0;
	}
	glw->setFileName(argv[1]);
    win window(glw);
	window.generateWindow();
    window.show();
    app.exec();
	return 0;
}
